<?php
/**
 * Глобальный класс управления структурами данных
 * 
 * @category Phorm
 * @package Structures
 * @name /Phorm/Structures.php
 * @copyright phorm.ru
 * @since 09.03.2012
 * @author vladimir@kachalov.net
 */

class Phorm_Structures extends Phorm_Model {
	
	/**
	 * Возвращает список свойств
	 *
	 * @param array $options
	 * @return array
	 */
	
	public function getPropertiesList($options = array()) {
		
		$select = $this->_db->select()
				-> from(array('AA'=>'pw_structures_properties'), 
										new Zend_Db_Expr("SQL_CALC_FOUND_ROWS AA.*, 'actions' actions"))
				-> where('isexist=?','yes');
				
		// Сортировки
		if(isset($options['sortField']) && in_array($options['sortField'],array('propertyid','propertyname','propertytype','ismultiple','visible'))) {
			$sortOrder = isset($options['sortOrder']) && $options['sortOrder']=='desc' ? ' DESC' : ' ASC';
			$select -> order($options['sortField'].$sortOrder);
		} else {
			$select -> order('sortorder');
			$select -> order('propertyname');
		}
		
		// Устанавливаем количество отдаваемых строк
		// Если передан 0, то возвращаем все найденные строки
		if (isset($options['rowsperpage']) && $options['rowsperpage']>0) {
			$select -> limitPage($this->getCurrentPage(),(int)$options['rowsperpage']);
		} elseif(!isset($options['rowsperpage'])) {
			$select -> limitPage($this->getCurrentPage(),$this->getPerPage());
		}
		
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!="control") $select -> where('visible=?','yes');
				
		return $this->_db->fetchAll($select);
		
	}
	
	/**
	 * Возвращает список свойств в виде массива пар
	 *
	 * @param array $options
	 * @return array
	 */
	
	public function getPropertiesListAsPairs($options = array()) {
		
		$select = $this->_db->select()
				-> from('pw_structures_properties',array('propertyid','propertyname'))
				-> order('propertyname')
				-> where('isexist=?','yes');
				
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!="control") $select -> where('visible=?','yes');
				
		return $this->_db->fetchPairs($select);
		
	}
	
	
	/**
	 * Возвращает информацию о свойстве
	 *
	 * @param int $propertyid
	 * @return array
	 */
	
	public function getPropertyInfo($propertyid) {
		
		$select = $this->_db->select()
				-> from('pw_structures_properties')
				-> where('propertyid=?',$propertyid)
				-> where('isexist=?','yes');
				
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!='control') $select -> where('visible=?','yes');
				
		if($row = $this->_db->fetchRow($select)) {
			$row['propertyoptions'] = explode(PHP_EOL,$row['propertyoptions']);
			return $row;
		}
		
		return false;
		
	}
	
	
	/**
	 * Возвращает форму создания/редактирования свойства
	 *
	 * @param string $section
	 * @return Phorm_Form
	 */
	
	public function getPropertyForm($section = 'addproperty') {
		
		$form = new Phorm_Form('forms/control/structures.xml',$section);
		
		if($element = $form->getElement('structureid')) {
			$element->setMultiOptions($this->getStructuresListAsPairs());
		}
		
		if($element = $form->getElement('dictionaryid')) {
			$Dictionaries = new Phorm_Dictionaries();
			$element->setMultiOptions($Dictionaries->getDictionariesListAsPairs());
		}

		return $form;
		
	}
	
	
	/**
	 * Возвращает форму создания/редактирования свойства в зависимости от выбранного типа свойства
	 *
	 * @param array $data Массив данных формы (обычно, чистый массив $_POST)
	 * @param Phorm_Form $form Объект изначальной формы из self::getPropertyForm
	 * @return Phorm_Form Модифицированный объект формы, который и надо валидировать в контроллере
	 */
	
	public function getPropertyFormModified(array $data, Phorm_Form $form) {
		
		if(isset($data['propertytype'])) {
			if($data['propertytype']=='select') {
				$form->getElement('structureid')->setRequired(false);
				$form->getElement('dictionaryid')->setRequired(false);
			} elseif($data['propertytype']=='structure') {
				$form->getElement('propertyoptions')->setRequired(false);
				$form->getElement('dictionaryid')->setRequired(false);
			} elseif($data['propertytype']=='dictionary') {
				$form->getElement('propertyoptions')->setRequired(false);
				$form->getElement('structureid')->setRequired(false);
			} else {
				$form->getElement('structureid')->setRequired(false);
				$form->getElement('dictionaryid')->setRequired(false);
				$form->getElement('propertyoptions')->setRequired(false);
				$form->getElement('ismultiple')->setRequired(false);
			}
		}
		
		return $form;
		
	}
	
	
	/**
	 * Возвращает оригинальную форму создания/редактирования свойства после ее модификации
	 *
	 * @param Phorm_Form $form Объект модифицированной формы из self::getPropertyFormModified
	 * @return Phorm_Form Оригинальный объект формы, который и надо кидать в шаблон
	 */
	
	public function getPropertyFormOriginal(Phorm_Form $form) {
		
		$form->getElement('structureid')->setRequired(true);
		$form->getElement('propertyoptions')->setRequired(true);
		$form->getElement('ismultiple')->setRequired(true);
		
		return $form;
		
	}
	
	
	/**
	 * Сохраняет свойство
	 *
	 * @param Phorm_Form $form
	 * @param mixed $data  Дополнительные данные формы. Если передана строка, то принимается как propertyid
	 * @return array | false
	 */
	
	public function savePropertyForm(Phorm_Form $form, $data = null) {
		
		if(!is_null($data) && is_string($data)) $data = array('propertyid'=>$data);
		$data = array_merge($form->getValues(),(array)$data);
		
		switch ($data['propertytype']) {
			
			case 'select':
				
				$data['propertyoptions'] = join(PHP_EOL,$data['propertyoptions']);
				unset($data['structureid'],$data['dictionaryid']);
				break;
				
			case 'structure':
				
				unset($data['propertyoptions'],$data['dictionaryid']);
				break;
				
			case 'dictionary':
				
				unset($data['propertyoptions'],$data['structureid']);
				break;
				
			default:
				
				unset($data['structureid'],$data['dictionaryid'],$data['propertyoptions'],$data['ismultiple']);
			
		}
		
		$data = $this->getFilteredValuesByTableCols('pw_structures_properties',$data);
		
		$this->_db->beginTransaction();
		
		try {
			
			// Изменение существующей записи
			if(isset($data['propertyid'])) {
				
				$this->_db->update('pw_structures_properties',$data,'propertyid='.(int)$data['propertyid']);
				
			// Вставка новой записи
			} else {
				
				$this->_db->insert('pw_structures_properties',$data);
				$data['propertyid'] = $this->_db->lastInsertId();
				
			}
			
			$this->_db->commit();						  
			return $data;
			
		} catch (Exception $e) {
			
			$this->_db->rollBack();	
			$this->_errors[] = $e->getMessage();
			
		}
		
		return false;
		
	}
	
	
	/**
	 * Возвращает список групп
	 *
	 * @param array $options
	 * @return array
	 */
	
	public function getGroupsList($options = array()) {
		
		$select = $this->_db->select()
				-> from(array('AA'=>'pw_structures_groups'), 
										new Zend_Db_Expr("SQL_CALC_FOUND_ROWS AA.*, 
															LENGTH(properties)-LENGTH(REPLACE(properties,',',''))+1 propertycount,
															'actions' actions"))
				-> where('isexist=?','yes');
				
		// Сортировки
		if(isset($options['sortField']) && in_array($options['sortField'],array('groupid','groupname','visible','propertycount'))) {
			$sortOrder = isset($options['sortOrder']) && $options['sortOrder']=='desc' ? ' DESC' : ' ASC';
			$select -> order($options['sortField'].$sortOrder);
		} else {
			$select -> order('sortorder');
			$select -> order('groupname');
		}
		
		// Устанавливаем количество отдаваемых строк
		// Если передан 0, то возвращаем все найденные строки
		if (isset($options['rowsperpage']) && $options['rowsperpage']>0) {
			$select -> limitPage($this->getCurrentPage(),(int)$options['rowsperpage']);
		} elseif(!isset($options['rowsperpage'])) {
			$select -> limitPage($this->getCurrentPage(),$this->getPerPage());
		}

		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!="control") $select -> where('visible=?','yes');
				
		return $this->_db->fetchAll($select);
		
	}
	
	
	/**
	 * Возвращает список групп в виде массива пар
	 *
	 * @param array $options
	 * @return array
	 */
	
	public function getGroupsListAsPairs($options = array()) {
		
		$select = $this->_db->select()
				-> from('pw_structures_groups',array('groupid','groupname'))
				-> order('groupname')
				-> where('isexist=?','yes');
				
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!="control") $select -> where('visible=?','yes');
				
		return $this->_db->fetchPairs($select);
		
	}
	
	
	/**
	 * Возвращает информацию о группе
	 *
	 * @param int $groupid
	 * @return array
	 */
	
	public function getGroupInfo($groupid) {
		
		$select = $this->_db->select()
				-> from('pw_structures_groups')
				-> where('groupid=?',$groupid)
				-> where('isexist=?','yes');
				
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!='control') $select -> where('visible=?','yes');
				
		if($row = $this->_db->fetchRow($select)) {
			$row['properties'] = explode(',',$row['properties']);
			return $row;
		}
		
		return false;
		
	}
	
	
	/**
	 * Сохраняет группу
	 *
	 * @param Phorm_Form $form
	 * @param mixed $data  Дополнительные данные формы. Если передана строка, то принимается как groupid
	 * @return array | false
	 */
	
	public function saveGroupForm(Phorm_Form $form, $data = null) {
		
		if(!is_null($data) && is_string($data)) $data = array('groupid'=>$data);
		$data = array_merge($form->getValues(),(array)$data);
		
		$data['properties'] = join(',',$data['properties']);
		
		$data = $this->getFilteredValuesByTableCols('pw_structures_groups',$data);
		
		$this->_db->beginTransaction();
		
		try {
			
			// Изменение существующей записи
			if(isset($data['groupid'])) {
				
				$this->_db->update('pw_structures_groups',$data,'groupid='.(int)$data['groupid']);
				
			// Вставка новой записи
			} else {
				
				$this->_db->insert('pw_structures_groups',$data);
				$data['groupid'] = $this->_db->lastInsertId();
				
			}
			
			$this->_db->commit();						  
			return $data;
			
		} catch (Exception $e) {
			
			$this->_db->rollBack();	
			$this->_errors[] = $e->getMessage();
			
		}
		
		return false;
		
	}
	
	
	/**
	 * Возвращает список структур
	 *
	 * @param array $options
	 * @return array
	 */
	
	public function getStructuresList($options = array()) {
		
		$select = $this->_db->select()
				-> from(array('AA'=>'pw_structures'), 
										new Zend_Db_Expr("SQL_CALC_FOUND_ROWS AA.*, 
															LENGTH(groups)-LENGTH(REPLACE(groups,',',''))+1 groupscount,
															'actions' actions"))
				-> where('isexist','yes');
				
		// Сортировки
		if(isset($options['sortField']) && in_array($options['sortField'],array('structureid','structurename','visible','groupscount'))) {
			$sortOrder = isset($options['sortOrder']) && $options['sortOrder']=='desc' ? ' DESC' : ' ASC';
			$select -> order($options['sortField'].$sortOrder);
		} else {
			$select -> order('structurename');
		}
		
		// Устанавливаем количество отдаваемых строк
		// Если передан 0, то возвращаем все найденные строки
		if (isset($options['rowsperpage']) && $options['rowsperpage']>0) {
			$select -> limitPage($this->getCurrentPage(),(int)$options['rowsperpage']);
		} elseif(!isset($options['rowsperpage'])) {
			$select -> limitPage($this->getCurrentPage(),$this->getPerPage());
		}
		
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!="control") $select -> where('visible=?','yes');
				
		return $this->_db->fetchAll($select);
		
	}
	
	
	/**
	 * Возвращает список всех структур в виде массива пар
	 *
	 * @return array
	 */
	
	public function getStructuresListAsPairs() {
		
		$select = $this->_db->select()
				-> from('pw_structures',array('structureid','structurename'))
				-> where('isexist','yes')
				-> order('structurename');
		
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!='control') $select -> where('visible=?','yes');
				
		return $this->_db->fetchPairs($select);
		
	}
	
	
	/**
	 * Возвращает информацию о структуре
	 *
	 * @param int $structureid
	 * @return array
	 */
	
	public function getStructureInfo($structureid) {
		
		$select = $this->_db->select()
				-> from('pw_structures')
				-> where('structureid=?',$structureid)
				-> where('isexist=?','yes');
				
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!='control') $select -> where('visible=?','yes');
				
		if($row = $this->_db->fetchRow($select)) {
			$row['groups'] = explode(',',$row['groups']);
			return $row;
		}
		
		return false;
		
	}
	
	
	/**
	 * Возвращает полную информацию о структуре (структура, группы и свойства)
	 *
	 * @param int $structureid
	 * @return array
	 * @todo Сделать выборку списка групп и свойств одним запросом
	 */
	
	public function getStructureFullInfo($structureid) {
				
		if($row = $this->getStructureInfo($structureid)) {
			
			$groups = $row['groups'];
			$row['groups'] = array();
			
			foreach ($groups as $groupid) {
				
				$groupinfo = $this->getGroupInfo($groupid);
				
				$properties = $groupinfo['properties'];
				$groupinfo['properties'] = array();
				
				foreach ($properties as $propertyid) {
					$groupinfo['properties'][$propertyid] = $this->getPropertyInfo($propertyid);
				}
				
				$row['groups'][$groupid] = $groupinfo;
				
			}
			
			return $row;
			
		}
		
		return false;
		
	}
	
	
	/**
	 * Сохраняет структуру
	 *
	 * @param Phorm_Form $form
	 * @param mixed $data  Дополнительные данные формы. Если передана строка, то принимается как structureid
	 * @return array | false
	 */
	
	public function saveStructureForm(Phorm_Form $form, $data = null) {
		
		if(!is_null($data) && is_string($data)) $data = array('structureid'=>$data);
		$data = array_merge($form->getValues(),(array)$data);
		
		$data['groups'] = join(',',$data['groups']);
		
		$data = $this->getFilteredValuesByTableCols('pw_structures',$data);
		
		$this->_db->beginTransaction();
		
		try {
			
			// Изменение существующей записи
			if(isset($data['structureid'])) {
				
				$this->_db->update('pw_structures',$data,'structureid='.(int)$data['structureid']);
				
			// Вставка новой записи
			} else {
				
				$this->_db->insert('pw_structures',$data);
				$data['structureid'] = $this->_db->lastInsertId();
				
			}
			
			$this->_db->commit();						  
			return $data;
			
		} catch (Exception $e) {
			
			$this->_db->rollBack();	
			$this->_errors[] = $e->getMessage();
			
		}
		
		return false;
		
	}
	
	
	/**
	 * Удаляет запись из таблиц структур данных
	 *
	 * @param string $table
	 * @param int $identity
	 * @return boolean
	 */
	
	public function deleteResource($table,$identity) {
		
		$map = array(
			'structures' => array('table' => 'pw_structures', 'id' => 'structureid'),
			'groups' => array('table' => 'pw_structures_groups', 'id' => 'groupid'),
			'properties' => array('table' => 'pw_structures_properties', 'id' => 'propertyid'),
		);
		
		return $this->_db->update($map[$table]['table'],array('isexist'=>'no'),$map[$table]['id'].'='.(int)$identity);
		
	}
	
	
	/**
	 * Возвращает список материалов из заданной структуры в виде массива пар
	 *
	 * @param int $structureid Id структуры
	 * @return array
	 */
	
	public function getStructureResourcesAsPairs($structureid) {
		
		$select = $this->_db->select()
				-> distinct()
				-> from(array('AA'=>'pw_resources'),array('resourceid','resourcename'))
				-> join(array('BB'=>'pw_resources_structures'),'AA.resourceid=BB.resourceid')
				-> join(array('CC'=>'pw_structures'),'BB.structureid=CC.structureid')
				-> join(array('DD'=>'pw_structures_groups'),'BB.groupid=DD.groupid')
				-> join(array('EE'=>'pw_structures_properties'),'BB.propertyid=EE.propertyid')
				-> where('AA.isexist=?','yes')
				-> where('BB.structureid=?',$structureid)
				-> where('CC.isexist=?','yes')
				-> where('DD.isexist=?','yes')
				-> where('EE.isexist=?','yes')
				-> order('resourcename');
				
		// Добавляем условие, если выборка для фронтенда
		if($this->getModule()!="control") {
			$select -> where('AA.visible=?','yes')
					-> where('CC.visible=?','yes')
					-> where('DD.visible=?','yes')
					-> where('EE.visible=?','yes');
		}
		
		return $this->_db->fetchPairs($select);
		
	}
	
}